package com.saikuo.service.service.impl;

import com.saikuo.service.api.ApiResultModel;
import com.saikuo.service.api.ErrorCode;
import com.saikuo.service.constant.Config;
import com.saikuo.service.constant.ContextConfig;
import com.saikuo.service.constant.SmsCodeType;
import com.saikuo.service.constant.UserStatus;
import com.saikuo.service.dao.IUserDao;
import com.saikuo.service.model.User;
import com.saikuo.service.service.IUserService;
import com.saikuo.service.utils.SmsUtils;
import com.saikuo.service.vo.UserAddressView;
import com.saikuo.service.vo.UserView;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by shanchangyu on 16/10/14.
 */
@Service
public class UserServiceImpl implements IUserService {


    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private IUserDao userDao;

    @Autowired
    private Config config;

    private static final String VERIFY_CODE_PRE = "【药到】您的验证码是:";
    private static final String VERIFY_CODE_POST = "，有效期3分钟；如非本人操作,请忽略本消息。";
    private static final String REGISTER_CODE_PRE = "【药到】恭喜您注册成功，您的初始密码:" ;
    private static final String REGISTER_CODE_END = ",请尽快修改密码；如非本人操作,请忽略本消息。";
    private static final long CACHE_TIME = 3;

    @Override
    public ApiResultModel sendVerifyCode(String mobile, int codeType) {
        SmsCodeType smsCodeType = SmsCodeType.findByValue(codeType);
        if (smsCodeType != null) {
            if (smsCodeType.name().equals(SmsCodeType.REGISTER.name())) {
                if (userDao.mobileExist(mobile)) {
                    return new ApiResultModel(ErrorCode.MOBILE_ALREADY_REGIST);
                }
            }
            this.sendCode(mobile);
        } else {
            return new ApiResultModel(ErrorCode.SMS_CODE_TYPE_FAIL);
        }
        return new ApiResultModel();
    }

    @Override
    public ApiResultModel register(String verifyCode, String mobile, String password) {
        if (!verifyTheCode(mobile, verifyCode)) {
            return new ApiResultModel(ErrorCode.VERIFY_CODE_FAIL);
        }
        String encrptedPassword = DigestUtils.md5Hex(password);
        boolean result = userDao.register(mobile, encrptedPassword);
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        User user = userDao.getUserByMobile(mobile);
        return new ApiResultModel(new UserView(user));
    }

    @Override
    public ApiResultModel forgetPassword(String verifyCode, String mobile, String newPassword) {
        if (!verifyTheCode(mobile, verifyCode)) {
            return new ApiResultModel(ErrorCode.VERIFY_CODE_FAIL);
        }
        String encrptedPassword = DigestUtils.md5Hex(newPassword);
        boolean result = userDao.updatePassword(mobile, encrptedPassword);
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        return new ApiResultModel();
    }

    @Override
    public ApiResultModel pwdLogin(String mobile, String password) {
        User user = userDao.getUserByMobile(mobile);
        if (user == null) {
            return new ApiResultModel(ErrorCode.USER_NOT_EXIST);
        }
        String encrpytPassword = DigestUtils.md5Hex(password);
        if (!encrpytPassword.equals(user.getPassword())) {
            return new ApiResultModel(ErrorCode.PASSWORD_ERROR);
        }
        if (user.getStatus() == UserStatus.FREEZE.ordinal()) {
            return new ApiResultModel(ErrorCode.USER_FREEZED);
        }
        return new ApiResultModel(new UserView(user));
    }


    @Override
    public ApiResultModel codeLogin(String mobile, String verifyCode) {

        if (!verifyTheCode(mobile, verifyCode)) {
            return new ApiResultModel(ErrorCode.VERIFY_CODE_FAIL);
        }
        User user = userDao.getUserByMobile(mobile);
        if (user == null) {
            int smsCode = (int) ((Math.random() * 9 + 1) * 100000);
            String pwd = DigestUtils.md5Hex(String.valueOf(smsCode));
            userDao.register(mobile, DigestUtils.md5Hex(pwd));
            SmsUtils.sendMsg(mobile,REGISTER_CODE_PRE+smsCode+REGISTER_CODE_END);
            user = userDao.getUserByMobile(mobile);
        }
        return new ApiResultModel(new UserView(user));
    }


    @Override
    public ApiResultModel changePassword(int userId, String oldPassword, String newPassword) {
        String userPassword = userDao.getPasswordByUid(userId);
        if (!userPassword.equals(DigestUtils.md5Hex(oldPassword))) {
            return new ApiResultModel(ErrorCode.PASSWORD_ERROR);
        }
        boolean result = userDao.changePasswordByUid(userId,
                DigestUtils.md5Hex(newPassword));
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        return new ApiResultModel();
    }

    private boolean verifyTheCode(String mobile, String code) {
        if (StringUtils.isEmpty(code)) {
            return false;
        }
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String cacheCode = valueOperations.get(mobile);
        if (code.equals(cacheCode)) {
            redisTemplate.delete(mobile);
            return true;
        }
        return false;
    }

    @Override
    public ApiResultModel addUserAddress(int userId, String mobile, String address, String name, Double lat, Double lng, String cityCode, String areaCode) {
        List<UserAddressView> userAddressViews = userDao.getUserAddressByUserId(userId);
        if (userAddressViews != null && userAddressViews.size() > ContextConfig.ADDRESS_NUM_SIZE - 1) {
            return new ApiResultModel(ErrorCode.USER_ADDRESS_NUM_OVER);
        }
        UserAddressView userAddressView = new UserAddressView();
        userAddressView.setUserId(userId);
        userAddressView.setName(name);
        userAddressView.setMobile(mobile);
        userAddressView.setAddress(address);
        userAddressView.setLat(lat);
        userAddressView.setLng(lng);
        userAddressView.setCityCode(cityCode);
        userAddressView.setAreaCode(areaCode);
        int userAddressId = userDao.addUserAddress(userAddressView);
        if (userAddressId > 0) {
            userAddressView.setId(userAddressId);
            return new ApiResultModel(userAddressView);
        }
        return new ApiResultModel(ErrorCode.DATABASE_ERROR);
    }

    @Override
    public ApiResultModel updateUserAddress(int id, String mobile, String address, String name, Double lat, Double lng, String cityCode, String areaCode) {
        boolean result = userDao.updateUserAddress(id, mobile, address, name, lat, lng, cityCode, areaCode);
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        return new ApiResultModel();
    }

    @Override
    public ApiResultModel getUserAddressById(int id) {
        UserAddressView userAddressView = userDao.getUserAddressById(id);
        if (userAddressView == null) {
            return new ApiResultModel(ErrorCode.USER_ADDRESS_NOT_EXIST);
        }
        return new ApiResultModel(userAddressView);
    }

    @Override
    public ApiResultModel getUserAddressByUserId(int userId) {
        return new ApiResultModel(userDao.getUserAddressByUserId(userId));
    }

    @Override
    public ApiResultModel deleteUserAddressById(int id) {
        boolean result = userDao.deleteUserAddressById(id);
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        return new ApiResultModel();
    }


    private boolean sendCode(String mobile) {
        int smsCode = (int) ((Math.random() * 9 + 1) * 100000);
        String content = VERIFY_CODE_PRE + smsCode + VERIFY_CODE_POST;
        boolean result = SmsUtils.sendMsg(mobile, content);
        if (result) {//放入redis缓存
            ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
            valueOperations.set(mobile, String.valueOf(smsCode),
                    CACHE_TIME, TimeUnit.MINUTES);
        }
        return result;
    }

    @Override
    public ApiResultModel createFeedBack(int userId, String message) {
        boolean result = userDao.createFeedBack(userId, message);
        if (!result) {
            return new ApiResultModel(ErrorCode.DATABASE_ERROR);
        }
        return new ApiResultModel();
    }

}
